#ifndef _REF_PTR_
#define _REF_PTR_


//////////////////////////////////////////////////////////////////////

#include <ostream>

/** Base class from providing referencing counted objects.*/
class Referenced
{

    public:


        Referenced(); 
        
        Referenced(const Referenced&);

        inline Referenced& operator = (const Referenced&) { return *this; }

        /** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/
        void setThreadSafeRefUnref(bool threadSafe);

        /** Get whether a mutex is used to ensure ref() and unref() are thread safe.*/
       // bool getThreadSafeRefUnref() const { return _refMutex!=0; }

        /** Increment the reference count by one, indicating that 
            this object has another pointer which is referencing it.*/
        inline void ref() const;
        
        /** Decrement the reference count by one, indicating that 
            a pointer to this object is referencing it.  If the
            reference count goes to zero, it is assumed that this object
            is no longer referenced and is automatically deleted.*/
        inline void unref() const;
        
        /** Decrement the reference count by one, indicating that 
            a pointer to this object is referencing it.  However, do
            not delete it, even if ref count goes to 0.  Warning, unref_nodelete() 
            should only be called if the user knows exactly who will
            be resonsible for, one should prefer unref() over unref_nodelete() 
            as the later can lead to memory leaks.*/
        void unref_nodelete() const;
        
        /** Return the number pointers currently referencing this object. */
        inline int referenceCount() const { return _refCount; }


    public:

        /** Set whether reference counting should be use a mutex to create thread reference counting.*/
        static void setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting);
        
        /** Get whether reference counting is active.*/
        static bool getThreadSafeReferenceCounting();

        friend class DeleteHandler;

        /** Set a DeleteHandler to which deletion of all referenced counted objects
          * will be delegated to.*/
        static void setDeleteHandler(DeleteHandler* handler);

        /** Get a DeleteHandler.*/
        static DeleteHandler* getDeleteHandler();

       
    protected:
        virtual ~Referenced();
        
//        mutable OpenThreads::Mutex*  _refMutex;

        mutable int                  _refCount;
        
};


/** Class for override the default delete behavior so that users can implment their own object
  * deletion schemes.  This might be done to help implement protection of multiple threads from deleting
  * objects unintentionally.
  * Note, the DeleteHandler cannot itself be reference counted, otherwise it
  * would be responsible for deleting itself!
  * An static auto_ptr<> is used internally in Referenced.cpp to manage the 
  * DeleteHandler's memory.*/
class DeleteHandler
{
    public:

        virtual ~DeleteHandler() {}

        /** flush any cache of objects that need to be deleted by doing an actual delete.*/
        virtual void flush() {}
        
        inline void doDelete(const Referenced* object) { delete object; }
         
        /** Request the deletion of an object. 
          * Depending on users implementation of DeleteHandler, the delete of the object may occur 
          * straight away or be delayed until doDelete is called.
          * The default implementation does a delete straight away.*/
        virtual void requestDelete(const Referenced* object) { doDelete(object); }
};

inline void Referenced::ref() const
{
//    if (_refMutex)
   // {
  //      OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex); 
        ++_refCount;
  //  }
  //  else
    {
        ++_refCount;
    }
}

inline void Referenced::unref() const
{
    bool needDelete = false;
//    if (_refMutex)
 //   {
  //      OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex); 
  //      --_refCount;
  //      needDelete = _refCount<=0;
   // }
   // else
    {
        --_refCount;
        needDelete = _refCount<=0;
    }

    if (needDelete)
    {
       // if (getDeleteHandler()) getDeleteHandler()->requestDelete(this);
        //else
		delete this;
    }
}




/** Smart pointer for handling referenced counted objects.*/
   template<class T>
   class RefPtr
   {

   public:
      typedef T element_type;

      RefPtr() :_ptr(0L) {}
      RefPtr(T* t):_ptr(t)              { if (_ptr) _ptr->ref(); }
      RefPtr(const RefPtr& rp):_ptr(rp._ptr)  { if (_ptr) _ptr->ref(); }
      ~RefPtr()                           { if (_ptr) _ptr->unref(); _ptr=0; }

      inline RefPtr& operator = (const RefPtr& rp)
      {
      if (_ptr==rp._ptr) return *this;
      T* tmp_ptr = _ptr;
      _ptr = rp._ptr;
      if (_ptr) _ptr->ref();
      // unref second to prevent any deletion of any object which might
      // be referenced by the other object. i.e rp is child of the
      // original _ptr.
      if (tmp_ptr) tmp_ptr->unref();
      return *this;
      }

      inline RefPtr& operator = (T* ptr)
      {
      if (_ptr==ptr) return *this;
      T* tmp_ptr = _ptr;
      _ptr = ptr;
      if (_ptr) _ptr->ref();
      // unref second to prevent any deletion of any object which might
      // be referenced by the other object. i.e rp is child of the
      // original _ptr.
      if (tmp_ptr) tmp_ptr->unref();
      return *this;
      }

      // comparison operators for RefPtr.
      inline bool operator == (const RefPtr& rp) const { return (_ptr==rp._ptr); }
      inline bool operator != (const RefPtr& rp) const { return (_ptr!=rp._ptr); }
      inline bool operator < (const RefPtr& rp) const { return (_ptr<rp._ptr); }
      inline bool operator > (const RefPtr& rp) const { return (_ptr>rp._ptr); }

      // comparison operator for const T*.
      inline bool operator == (const T* ptr) const { return (_ptr==ptr); }
      inline bool operator != (const T* ptr) const { return (_ptr!=ptr); }
      inline bool operator < (const T* ptr) const { return (_ptr<ptr); }
      inline bool operator > (const T* ptr) const { return (_ptr>ptr); }

      //added for by Delta3D
      friend inline std::ostream &operator<<(std::ostream &os,
         const RefPtr& rp)
      {
         os << rp._ptr;
         return os;
      }

      inline T& operator*()  { return *_ptr; }

      inline const T& operator*() const { return *_ptr; }

      inline T* operator->() { return _ptr; }

      inline const T* operator->() const   { return _ptr; }

      inline bool operator!() const	{ return _ptr==0L; }

      inline bool valid() const	{ return _ptr!=0L; }

      inline T* get() { return _ptr; }

      inline const T* get() const { return _ptr; }

      inline T* take() { return release();}

      inline T* release() { T* tmp=_ptr; if (_ptr) _ptr->unref_nodelete(); _ptr=0; return tmp;}

      private:
      T* _ptr;
     
   };
#endif 